﻿using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using Lenic.DI.Lifetimes;

namespace Lenic.DI
{
    /// <summary>
    /// Container Events Builder
    /// </summary>
    [DebuggerStepThrough]
    public sealed class ContainerEventsBuilder : INotifiedObject
    {
        #region Private Fields

        private event PreprocessNotifiedObject onBeforeResolve;

        private event ProcessNotifiedObject onRoundResolve;

        private event PostprocessNotifiedObject onAfterResolve;

        private IDictionary<MemberInfo, object> onBeforeResolveDic = new Dictionary<MemberInfo, object>();
        private IDictionary<MemberInfo, object> onRoundResolveDic = new Dictionary<MemberInfo, object>();
        private IDictionary<MemberInfo, object> onAfterResolveDic = new Dictionary<MemberInfo, object>();

        #endregion Private Fields

        #region Entrance

        /// <summary>
        /// Initializes a new instance of the <see cref="ContainerEventsBuilder"/> class.
        /// </summary>
        public ContainerEventsBuilder()
        {
        }

        #endregion Entrance

        #region Business Methods

        /// <summary>
        /// Builds this container instance.
        /// </summary>
        /// <returns>The container instance.</returns>
        public IContainer Build(IContainer container)
        {
            foreach (var item in container)
            {
                BindingNotifiedEvents(item);
            }

            return container;
        }

        #endregion Business Methods

        #region INotifiedObject Members

        /// <summary>
        /// 对象解析前事件.
        /// </summary>
        public event PreprocessNotifiedObject OnBeforeResolve
        {
            add
            {
                MemberInfo mi = value.Method;
                if (!onBeforeResolveDic.ContainsKey(mi))
                {
                    onBeforeResolveDic[mi] = null;
                    onBeforeResolve += value;
                }
            }
            remove
            {
                if (onBeforeResolveDic.Remove(value.Method))
                    onBeforeResolve -= value;
            }
        }

        /// <summary>
        /// 对象解析时事件.
        /// </summary>
        public event ProcessNotifiedObject OnRoundResolve
        {
            add
            {
                MemberInfo mi = value.Method;
                if (!onRoundResolveDic.ContainsKey(mi))
                {
                    onRoundResolveDic[mi] = null;
                    onRoundResolve += value;
                }
            }
            remove
            {
                if (onRoundResolveDic.Remove(value.Method))
                    onRoundResolve -= value;
            }
        }

        /// <summary>
        /// 对象解析后事件.
        /// </summary>
        public event PostprocessNotifiedObject OnAfterResolve
        {
            add
            {
                MemberInfo mi = value.Method;
                if (!onAfterResolveDic.ContainsKey(mi))
                {
                    onAfterResolveDic[mi] = null;
                    onAfterResolve += value;
                }
            }
            remove
            {
                if (onAfterResolveDic.Remove(value.Method))
                    onAfterResolve -= value;
            }
        }

        #endregion INotifiedObject Members

        #region Private Methods

        /// <summary>
        /// 为生存周期实例对象绑定全局事件.
        /// </summary>
        /// <param name="lifetime">一个生存周期的实例对象.</param>
        private void BindingNotifiedEvents(ILifetime lifetime)
        {
            if (onBeforeResolveDic.Count > 0)
                lifetime.OnBeforeResolve += onBeforeResolve;

            if (onRoundResolveDic.Count > 0)
                lifetime.OnRoundResolve += onRoundResolve;

            if (onAfterResolveDic.Count > 0)
                lifetime.OnAfterResolve += onAfterResolve;
        }

        #endregion Private Methods
    }
}